#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import argparse
import logging
import json
from pathlib import Path

from app.core.joystick_controller import JoystickController
from app.config.joystick_config import JoystickConfig
from app.utils.joystick_detector import JoystickDetector

def setup_logging(log_level=logging.INFO, log_file=None):
    """
    设置日志配置
    
    :param log_level: 日志级别
    :param log_file: 日志文件路径
    """
    # 获取根日志记录器
    root_logger = logging.getLogger()
    
    # 清除所有已有的处理器，避免重复
    for handler in root_logger.handlers[:]:
        root_logger.removeHandler(handler)
    
    root_logger.setLevel(log_level)
    
    # 创建控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setLevel(log_level)
    
    # 设置日志格式
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
    
    # 添加控制台处理器
    root_logger.addHandler(console_handler)
    
    # 如果指定了日志文件，添加文件处理器
    if log_file:
        file_handler = logging.FileHandler(log_file)
        file_handler.setLevel(log_level)
        file_handler.setFormatter(formatter)
        root_logger.addHandler(file_handler)
        
    # 配置pygame日志级别，防止显示不必要的信息
    logging.getLogger('pygame').setLevel(logging.WARNING)

def detect_joysticks(args):
    """
    检测连接的游戏手柄
    
    :param args: 命令行参数
    :return: 0表示成功，非0表示失败
    """
    detector = JoystickDetector()
    
    try:
        joysticks = detector.list_joysticks()
        
        if not joysticks:
            print("未检测到游戏手柄设备")
            return 1
        
        print(f"检测到 {len(joysticks)} 个游戏手柄设备:")
        
        for i, js in enumerate(joysticks):
            print(f"设备 {i}:")
            print(f"  名称: {js['name']}")
            print(f"  GUID: {js['guid']}")
            print(f"  按钮数量: {js['num_buttons']}")
            print(f"  轴数量: {js['num_axes']}")
            print(f"  HAT数量: {js['num_hats']}")
        
        return 0
    finally:
        detector.cleanup()

def test_buttons(args):
    """
    测试游戏手柄按钮
    
    :param args: 命令行参数
    :return: 0表示成功，非0表示失败
    """
    detector = JoystickDetector()
    
    try:
        count = detector.get_joystick_count()
        
        if count == 0:
            print("未检测到游戏手柄设备")
            return 1
        
        device_id = args.device
        if device_id >= count:
            print(f"设备ID {device_id} 超出范围，可用设备数量: {count}")
            return 1
        
        print(f"开始测试设备 {device_id} 的按钮")
        print("请依次按下手柄上的每个按钮...")
        
        # 如果指定了映射文件但文件不存在，则创建一个空的映射文件
        if args.mapping and not os.path.exists(args.mapping):
            print(f"映射文件 {args.mapping} 不存在，将在测试后创建")
        
        # 将映射文件参数传递给测试函数
        button_map = detector.test_buttons(device_id, args.timeout, args.mapping)
        
        if not button_map:
            print("未检测到任何按钮按下")
            return 1
        
        print("\n按钮测试结果:")
        for button_id, button_name in sorted(button_map.items()):
            print(f"按钮 {button_id}: {button_name}")
        
        # 如果指定了输出文件，保存按钮映射
        if args.output:
            detector.create_button_mapping_file(button_map, args.output)
            print(f"按钮映射已保存到: {args.output}")
        
        return 0
    finally:
        detector.cleanup()

def generate_config(args):
    """
    生成配置文件
    
    :param args: 命令行参数
    :return: 0表示成功，非0表示失败
    """
    config = JoystickConfig()
    
    # 如果指定了模板文件，从模板加载
    if args.template and os.path.exists(args.template):
        try:
            with open(args.template, 'r', encoding='utf-8') as f:
                template = json.load(f)
            config.update_config(template)
            print(f"已从模板 {args.template} 加载配置")
        except Exception as e:
            print(f"加载模板文件失败: {str(e)}")
            return 1
    
    # 设置命令
    if args.command:
        for cmd_str in args.command:
            try:
                process_name, command = cmd_str.split('=', 1)
                config.set_command(process_name, command)
                print(f"已设置进程 '{process_name}' 的命令: {command}")
            except ValueError:
                print(f"命令格式错误: {cmd_str}，应为 'process_name=command'")
    
    # 设置按钮动作
    if args.button:
        for btn_str in args.button:
            try:
                parts = btn_str.split('=')
                if len(parts) < 2 or len(parts) > 3:
                    raise ValueError("格式错误")
                
                button_id = int(parts[0])
                action = parts[1]
                process_name = parts[2] if len(parts) > 2 else "default"
                
                config.set_button_action(button_id, action, process_name)
                print(f"已设置按钮 {button_id} 的动作: {action}, 进程: {process_name}")
            except ValueError:
                print(f"按钮配置格式错误: {btn_str}，应为 'button_id=action[=process_name]'")
    
    # 设置按键消抖时间
    if args.debounce_time is not None:
        try:
            debounce_time = float(args.debounce_time)
            config.set_debounce_time(debounce_time)
            print(f"已设置按键消抖时间: {debounce_time} 秒")
        except ValueError:
            print(f"无效的消抖时间: {args.debounce_time}，必须是一个数字")
    
    # 保存配置
    if config.save_config(args.output):
        print(f"配置已保存到: {args.output}")
        return 0
    else:
        print("保存配置失败")
        return 1

def run_controller(args):
    """
    运行游戏手柄控制器
    
    :param args: 命令行参数
    :return: 0表示成功，非0表示失败
    """
    config_file = args.config
    
    if not config_file or not os.path.exists(config_file):
        print(f"配置文件 {config_file} 不存在")
        return 1
    
    try:
        # 尝试创建一个默认配置
        if not os.path.exists(config_file):
            # 如果配置文件不存在，创建一个示例配置
            config = JoystickConfig()
            config.save_config(config_file)
            print(f"已创建默认配置文件: {config_file}")
        
        config = JoystickConfig(config_file)
        
        # 如果命令行指定了消抖时间，则覆盖配置文件中的设置
        if args.debounce_time is not None:
            try:
                debounce_time = float(args.debounce_time)
                config.set_debounce_time(debounce_time)
                print(f"已从命令行设置按键消抖时间: {debounce_time} 秒")
            except ValueError:
                print(f"无效的消抖时间: {args.debounce_time}，必须是一个数字")
                return 1
        
        controller = JoystickController(config.get_config())
        controller.run()
        return 0
    except KeyboardInterrupt:
        print("用户中断，退出")
        return 0
    except Exception as e:
        print(f"运行控制器时发生错误: {str(e)}")
        return 1

def main():
    """
    主程序入口
    """
    # 创建顶级解析器
    parser = argparse.ArgumentParser(description='游戏手柄进程控制工具')
    parser.add_argument('--log-level', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
                      default='INFO', help='日志级别 (默认: INFO)')
    parser.add_argument('--log-file', help='日志文件路径')
    
    # 创建子命令解析器
    subparsers = parser.add_subparsers(dest='command', help='子命令')
    
    # 检测命令
    detect_parser = subparsers.add_parser('detect', help='检测已连接的游戏手柄')
    
    # 测试按钮命令
    test_parser = subparsers.add_parser('test', help='测试游戏手柄按钮')
    test_parser.add_argument('--device', type=int, default=0, help='要测试的设备ID (默认: 0)')
    test_parser.add_argument('--timeout', type=int, default=30, help='测试超时时间（秒）(默认: 30)')
    test_parser.add_argument('--mapping', help='自定义按键映射文件路径')
    test_parser.add_argument('--output', help='保存按钮映射的输出文件路径')
    
    # 生成配置命令
    config_parser = subparsers.add_parser('config', help='生成配置文件')
    config_parser.add_argument('--template', help='配置模板文件路径')
    config_parser.add_argument('--command', action='append', help='设置进程命令，格式: process_name=command')
    config_parser.add_argument('--button', action='append', help='设置按钮动作，格式: button_id=action[=process_name]')
    config_parser.add_argument('--debounce-time', help='设置按键消抖时间（秒），默认为0.5秒')
    config_parser.add_argument('--output', required=True, help='配置输出文件路径')
    
    # 运行命令
    run_parser = subparsers.add_parser('run', help='运行游戏手柄控制器')
    run_parser.add_argument('--config', required=True, help='配置文件路径')
    run_parser.add_argument('--debounce-time', help='设置按键消抖时间（秒），会覆盖配置文件中的设置')
    
    # 解析命令行参数
    args = parser.parse_args()
    
    # 设置日志级别
    log_level = getattr(logging, args.log_level)
    setup_logging(log_level, args.log_file)
    
    # 根据子命令执行相应的功能
    if args.command == 'detect':
        return detect_joysticks(args)
    elif args.command == 'test':
        return test_buttons(args)
    elif args.command == 'config':
        return generate_config(args)
    elif args.command == 'run':
        return run_controller(args)
    else:
        parser.print_help()
        return 1

if __name__ == '__main__':
    sys.exit(main())
